package com.opgea.tutor.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.primefaces.model.UploadedFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.opgea.tutor.TutorException;
import com.opgea.tutor.dao.EducationDAO;
import com.opgea.tutor.dao.LocationDAO;
import com.opgea.tutor.dao.SpecializationDAO;
import com.opgea.tutor.dao.TutorDAO;
import com.opgea.tutor.dao.TutorDocumentDAO;
import com.opgea.tutor.domain.entities.Address;
import com.opgea.tutor.domain.entities.Education;
import com.opgea.tutor.domain.entities.Email;
import com.opgea.tutor.domain.entities.FileInfo;
import com.opgea.tutor.domain.entities.Location;
import com.opgea.tutor.domain.entities.Phone;
import com.opgea.tutor.domain.entities.Specialization;
import com.opgea.tutor.domain.entities.Tutor;
import com.opgea.tutor.domain.entities.TutorDocument;
import com.opgea.tutor.domain.model.PrimeFacesFileUploadBean;
import com.opgea.tutor.domain.qualifiers.TutorDocumentType;
import com.opgea.tutor.service.TutorService;
import com.opgea.tutor.web.dto.AddressDTO;
import com.opgea.tutor.web.dto.EducationDTO;
import com.opgea.tutor.web.dto.EmailDTO;
import com.opgea.tutor.web.dto.LocationDTO;
import com.opgea.tutor.web.dto.PhoneDTO;
import com.opgea.tutor.web.dto.SpecializationDTO;
import com.opgea.tutor.web.dto.TutorDTO;

@Service
@Transactional
public class TutorServiceImpl implements TutorService {

    @Autowired
    private TutorDAO tutorDAO;
    @Autowired
    private SpecializationDAO specializationDAO;
    @Autowired
    private LocationDAO locationDAO;
    @Autowired
    private EducationDAO educationDAO;
    @Autowired
    private TutorDocumentDAO documentDAO;

    @Override
    public TutorDTO create(TutorDTO tutorDTO) throws TutorException {
	if (tutorDTO.getId() == 0) {
	    Tutor tutor = new Tutor();
	    Address address = new Address();
	    Location location = new Location();
	    locationDAO.create(location);
	    tutor.setLocation(location);
	    tutor.setAddress(address);
	    tutorDTO.unmarshall(tutor);
	    tutorDAO.create(tutor);
	    tutorDTO.marshall(tutor);
	    return tutorDTO;
	} else {
	    return update(tutorDTO);
	}
    }

    @Override
    public TutorDTO update(TutorDTO tutorDTO) throws TutorException {
	Tutor tutor = tutorDAO.find(tutorDTO.getId());
	tutorDTO.unmarshall(tutor);
	tutorDAO.update(tutor);
	tutorDTO.marshall(tutor);
	return tutorDTO;
    }

    @Override
    public TutorDTO remove(Long id) throws TutorException {
	Tutor tutor = tutorDAO.find(id);
	TutorDTO tutorDTO = new TutorDTO();
	tutorDTO.marshall(tutor);
	tutorDAO.remove(tutor);
	return tutorDTO;
    }

    @Override
    public TutorDTO find(Long id) throws TutorException {
	Tutor tutor = tutorDAO.find(id);
	TutorDTO tutorDTO = new TutorDTO();
	tutorDTO.marshall(tutor);
	return tutorDTO;
    }

    @Override
    public List<TutorDTO> findAll() throws TutorException {
	Collection<Tutor> tutors = tutorDAO.findAll();
	List<TutorDTO> tutorDTOList = new ArrayList<TutorDTO>();
	for (Tutor tutor : tutors) {
	    TutorDTO tutorDTO = new TutorDTO();
	    tutorDTO.marshall(tutor);
	    tutorDTOList.add(tutorDTO);
	}
	return tutorDTOList;
    }

    @Override
    public TutorDTO findByLoginId(Long id) throws TutorException {
	Tutor tutor = tutorDAO.findTutorByLoginId(id);
	TutorDTO tutorDTO = new TutorDTO();
	tutorDTO.marshall(tutor);
	return tutorDTO;
    }

    @Override
    public AddressDTO findAddress(Long tutorId) throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	Address address = tutor.getAddress();
	AddressDTO addressDTO = new AddressDTO();
	addressDTO.marshall(address);
	return addressDTO;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<PhoneDTO> findPhoneNumbers(Long tutorId) throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Phone> phoneList = (List<Phone>) tutor.getPhoneNumbers();
	List<PhoneDTO> phoneDTOList = new ArrayList<PhoneDTO>();
	for (Phone phone : phoneList) {
	    PhoneDTO phoneDTO = new PhoneDTO();
	    phoneDTO.marshall(phone);
	    phoneDTOList.add(phoneDTO);
	}
	return phoneDTOList;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<EmailDTO> findEmailIds(Long tutorId) throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Email> emailList = (List<Email>) tutor.getEmailIds();
	List<EmailDTO> emailDTOList = new ArrayList<EmailDTO>();
	for (Email email : emailList) {
	    EmailDTO emailDTO = new EmailDTO();
	    emailDTO.marshall(email);
	    emailDTOList.add(emailDTO);
	}
	return emailDTOList;
    }

    @Override
    public AddressDTO updateAddress(Long tutorId, AddressDTO addressDTO)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	Address address = null;
	if (tutor.getAddress() == null) {
	    address = new Address();
	} else {
	    address = tutor.getAddress();
	}
	addressDTO.unmarshall(address);
	tutor.setAddress(address);
	tutorDAO.update(tutor);
	return addressDTO;
    }

    @SuppressWarnings("unchecked")
    @Override
    public PhoneDTO updatePhone(Long tutorId, PhoneDTO phoneDTO)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Phone> phoneList = (List<Phone>) tutor.getPhoneNumbers();
	Phone phone = new Phone();
	phoneDTO.unmarshall(phone);
	if (phoneList.contains(phone)) {
	    phoneList.remove(phone);
	}
	phoneList.add(phone);
	tutor.setPhoneNumbers(phoneList);
	tutorDAO.update(tutor);
	return phoneDTO;
    }

    @SuppressWarnings("unchecked")
    @Override
    public EmailDTO updateEmail(Long tutorId, EmailDTO emailDTO)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Email> emailList = (List<Email>) tutor.getEmailIds();
	Email email = new Email();
	emailDTO.unmarshall(email);
	if (emailList.contains(email)) {
	    emailList.remove(email);
	}
	emailList.add(email);
	tutorDAO.update(tutor);
	return emailDTO;
    }

    @Override
    public List<SpecializationDTO> findSpecializations(Long tutorId)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Specialization> specializationList = (List<Specialization>) tutor
		.getSpecializations();
	List<SpecializationDTO> specializationDTOList = new ArrayList<SpecializationDTO>();
	for (Specialization specialization : specializationList) {
	    SpecializationDTO specializationDTO = new SpecializationDTO();
	    specializationDTO.marshall(specialization);
	    specializationDTOList.add(specializationDTO);
	}
	return specializationDTOList;
    }

    @Override
    public SpecializationDTO updateSpecialization(Long tutorId,
	    SpecializationDTO specializationDTO) throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Specialization> specializations = (List<Specialization>) tutor
		.getSpecializations();
	Specialization specialization = new Specialization();
	specializationDTO.unmarshall(specialization);
	if (specializations.contains(specialization)) {
	    specializations.remove(specialization);
	} else {
	    specializationDAO.create(specialization);
	    specializations.add(specialization);
	}
	tutorDAO.update(tutor);
	return specializationDTO;
    }

    @Override
    public LocationDTO findLocation(Long tutorId) throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	Location location = tutor.getLocation();
	LocationDTO locationDTO = new LocationDTO();
	locationDTO.marshall(location);
	return locationDTO;
    }

    @Override
    public LocationDTO updateLocation(Long tutorId, LocationDTO locationDTO)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	Location location = tutor.getLocation();
	locationDTO.unmarshall(location);
	tutor.setLocation(location);
	tutorDAO.update(tutor);
	return locationDTO;
    }

    @Override
    public List<EducationDTO> findEducations(Long tutorId)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Education> educationList = (List<Education>) tutor.getEducations();
	List<EducationDTO> educationDTOList = new ArrayList<EducationDTO>();
	for (Education education : educationList) {
	    EducationDTO educationDTO = new EducationDTO();
	    educationDTO.marshall(education);
	    educationDTOList.add(educationDTO);
	}
	return educationDTOList;
    }

    @Override
    public EducationDTO updateEducation(Long tutorId, EducationDTO educationDTO)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Education> educations = (List<Education>) tutor.getEducations();
	Education education = new Education();
	educationDTO.unmarshall(education);
	if (educations.contains(education)) {
	    educations.remove(education);
	} else {
	    educationDAO.create(education);
	    educations.add(education);
	}
	tutorDAO.update(tutor);
	return educationDTO;
    }

    @Override
    public EducationDTO removeEducation(Long tutorId, Long educationDetailsId)
	    throws TutorException {
	Tutor tutor = tutorDAO.find(tutorId);
	List<Education> educations = (List<Education>) tutor.getEducations();
	Education education = educationDAO.find(educationDetailsId);
	if (educations.contains(education)) {
	    educations.remove(education);
	}
	tutorDAO.update(tutor);
	EducationDTO educationDTO = new EducationDTO();
	// educationDTO.unmarshall(education);
	return educationDTO;
    }

    @Override
    public void uploadDocument(Long tutorId,
	    PrimeFacesFileUploadBean pfFileUploadBean) throws TutorException {
	UploadedFile file = pfFileUploadBean.getFile();
	Tutor tutor = tutorDAO.find(tutorId);
	byte[] content = file.getContents();
	TutorDocument document = new TutorDocument();
	FileInfo fileInfo = new FileInfo();
	fileInfo.setExtension(file.getFileName().substring(
		file.getFileName().lastIndexOf(".")));
	fileInfo.setName(file.getFileName());
	fileInfo.setSize(file.getSize());

	document.setDocument(content);
	document.setDocumentType(TutorDocumentType.PERSONAL_IMAGE.toString());
	document.setFileInfo(fileInfo);
	documentDAO.create(document);
	tutor.addDocument(document);
	tutorDAO.update(tutor);
    }

    @Override
    public PrimeFacesFileUploadBean findDocumentByType(Long tutorId,
	    String documentType) throws TutorException {
	final TutorDocument document = documentDAO.findDocumentByType(tutorId,
		documentType);
	PrimeFacesFileUploadBean fileUploadBean = new PrimeFacesFileUploadBean();
	UploadedFile file = new UploadedFile() {

	    @Override
	    public long getSize() {
		return document.getDocument().length;
	    }

	    @Override
	    public InputStream getInputstream() throws IOException {
		// TODO Auto-generated method stub
		return null;
	    }

	    @Override
	    public String getFileName() {
		return document.getFileInfo().getName();
	    }

	    @Override
	    public byte[] getContents() {
		return document.getDocument();
	    }

	    @Override
	    public String getContentType() {
		return document.getFileInfo().getExtension();
	    }
	};
	fileUploadBean.setFile(file);
	return null;
    }

}
